package com.warren.system.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import com.warren.auth.utils.JwtTokenUtils;
import com.warren.handler.BusinessException;
import com.warren.response.Result;
import com.warren.response.ResultCode;
import com.warren.system.dto.LoginRequest;
import com.warren.system.entity.Department;
import com.warren.system.entity.Role;
import com.warren.system.entity.User;
import com.warren.enums.UserStatusEnum;
import com.warren.enums.UserTypeEnum;
import com.warren.system.mapper.DepartmentMapper;
import com.warren.system.mapper.RoleMapper;
import com.warren.system.mapper.UserMapper;

import com.warren.system.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.warren.system.vo.UserEditVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;


/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author warren
 * @since 2021-03-21
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtils jwtTokenUtil;

    @Value("${jwt.tokenHead}")
    private String tokenHead;


    @Override
    public IPage<User> findUserPage(Page<User> page, QueryWrapper<User> wrapper) {
        return this.baseMapper.findUserPage(page, wrapper);
    }

    @Override
    public void addUser(User user) {

        //判断是否增加了同一个用户
        String username = user.getUsername();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        Integer count = this.baseMapper.selectCount(wrapper);
        if (count != 0){
            throw new BusinessException(ResultCode.USER_ACCOUNT_ALREADY_EXIST.getCode(),
                    ResultCode.USER_ACCOUNT_ALREADY_EXIST.getMessage());
        }

        //获取部门
        Long departmentId = user.getDepartmentId();
        Department department = departmentMapper.selectById(departmentId);
        if (department == null){
            throw new BusinessException(ResultCode.DEPARTMENT_NOT_EXIST.getCode(),
                    ResultCode.DEPARTMENT_NOT_EXIST.getMessage());
        }

        String salt = UUID.randomUUID().toString().substring(0,32);
        user.setSalt(salt);
        //没有设置创建时间和更新 使用mybaits-plus的自藕丁填充功能实现
        //使用spring security自带的密码加载策略
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        //设置用户类型
        user.setType(UserTypeEnum.SYSTEM_USER.getTypeCode());
        //设置状态
        user.setStatus(UserStatusEnum.AVAILABLE.getStatusCode());
        //设置是否删除
        user.setDeleted(false);

        this.baseMapper.insert(user);
    }

    @Override
    public void exportUserExcel(HttpServletResponse response, List<User> users) throws IOException {
        //写入excel文件
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        String exportFileName = "UserInfo.xlsx";
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        response.addHeader("Content-disposition", "attachment;filename=" + exportFileName );
        EasyExcel.write(response.getOutputStream(), User.class).
                sheet("用户信息")
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .doWrite(users);
    }

    /**
     * 获取编辑用户用户信息
     * @param id
     * @return
     */
    @Override
    public UserEditVO edit(long id) throws BusinessException{
        User user = this.baseMapper.selectById(id);
        if (user == null){
            throw new BusinessException(ResultCode.USER_ACCOUNT_NOT_EXIST.getCode(),
                    ResultCode.USER_ACCOUNT_NOT_EXIST.getMessage());
        }
        UserEditVO userEditVO = new UserEditVO();
        BeanUtils.copyProperties(user,userEditVO);
        Department department = departmentMapper.selectById(user.getDepartmentId());
        if (department != null){
            userEditVO.setDepartmentId(department.getId());
        }
        return userEditVO;
    }

    /**
     * 更新编辑用户
     * @param id
     * @param userVO
     */
    @Override
    public void updateUser(long id,UserEditVO userVO) throws BusinessException{
        User dbUser = this.baseMapper.selectById(id);

        @NotNull(message = "部门不能为空") Long departmentId = userVO.getDepartmentId();

        if (dbUser == null){
            throw new BusinessException(ResultCode.USER_ACCOUNT_NOT_EXIST.getCode(),
                    ResultCode.USER_ACCOUNT_NOT_EXIST.getMessage());
        }

        Department department = departmentMapper.selectById(departmentId);
        if (department == null){
            throw new BusinessException(ResultCode.DEPARTMENT_NOT_EXIST.getCode(),
                    ResultCode.DEPARTMENT_NOT_EXIST.getMessage());
        }

        User user1 = new User();
        BeanUtils.copyProperties(userVO,user1);
        baseMapper.updateById(user1);
    }

    /**
     * 删除用户
     * @param id
     * @throws BusinessException
     */
    @Override
    public void deleteById(Long id) throws BusinessException {
        User user = this.baseMapper.selectById(id);

        if (user == null){
            throw new BusinessException(ResultCode.USER_ACCOUNT_NOT_EXIST.getCode()
                    ,ResultCode.USER_ACCOUNT_NOT_EXIST.getMessage());
        }
        //判断哪些角色不能删除,后续不上

        this.baseMapper.deleteById(id);
        //删除对应用户-角色记录
    }

    /**
     * 更新用户禁用状态
     * @param id
     * @param status
     * @throws BusinessException
     */
    @Override
    public void updateStatus(Long id, Boolean status) throws BusinessException {
        User dbUser = this.baseMapper.selectById(id);
        if(dbUser == null){
            throw new BusinessException(ResultCode.USER_ACCOUNT_NOT_EXIST.getCode(),
                    ResultCode.USER_ACCOUNT_NOT_EXIST.getMessage());
        }

        User t = new User();
        t.setId(id);
        t.setStatus(status ? UserStatusEnum.DISABLE.getStatusCode() :
                UserStatusEnum.AVAILABLE.getStatusCode());
        baseMapper.updateById(t);
    }

    @Override
    public User getAdminByUserName(String username) {
        return baseMapper.selectOne(new QueryWrapper<User>().eq("username",username));
    }

    @Override
    public List<Role> getRole(Long userId) {
        return roleMapper.getRoles(userId);
    }

    @Override
    public Result login( String code,LoginRequest loginRequest,HttpServletRequest request) {

        System.out.println(code);
        if (StringUtils.isEmpty(loginRequest.getVerifyCode()) || !code.equalsIgnoreCase(loginRequest.getVerifyCode())){
            return Result.error().message("验证码输入错误，请重新输入！");
        }

        //登录
        User user = getAdminByUserName(loginRequest.getUsername());

        if (null == user){
           return Result.error().message("用户名不存在");
        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername());
        if (null == userDetails || !passwordEncoder.matches(loginRequest.getPassword(),userDetails.getPassword())){
            return Result.error().message("用户名或密码错误");
        }

        if (!userDetails.isEnabled()){
            return Result.error(ResultCode.USER_ACCOUNT_DISABLE);
        }

        //更新security登录用户对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails
                , null, userDetails.getAuthorities());
        System.out.println(authenticationToken);
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        //设置security全局登陆用户
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        request.getServletContext().setAttribute("authenticationToken", SecurityContextHolder.getContext().getAuthentication());

        //生成token
        String token = jwtTokenUtil.generateToken(userDetails);
        System.out.println(token);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);

        return Result.ok().data("token",tokenMap);
    }
}
